/*
 * Copyright 2001-2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.axis.wsdl.toAS3;

import org.apache.axis.utils.Messages;
import org.apache.axis.wsdl.symbolTable.ContainedAttribute;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.wsdl.symbolTable.DefinedElement;
import org.apache.axis.wsdl.symbolTable.DefinedType;
import org.apache.axis.wsdl.symbolTable.ElementDecl;
import org.apache.axis.wsdl.symbolTable.SchemaUtils;
import org.apache.axis.wsdl.symbolTable.TypeEntry;
import org.apache.axis.wsdl.symbolTable.CollectionTE;

import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Vector;
import java.util.Set;

/**
 * This is Wsdl2java's Helper Type Writer.  It writes the <typeName>.java file.
 */
public class AS3BeanHelperWriter extends AS3ClassWriter {

    /** Field type */
    protected TypeEntry type;

    /** Field elements */
    protected Vector elements;

    /** Field attributes */
    protected Vector attributes;

    /** Field extendType */
    protected TypeEntry extendType;

    /** Field wrapperPW */
    protected PrintWriter wrapperPW = null;

    /** Field elementMetaData */
    protected Vector elementMetaData = null;

    /** Field canSearchParents */
    protected boolean canSearchParents;

    /** Field reservedPropNames */
    protected Set reservedPropNames;

    /**
     * Constructor.
     * 
     * @param emitter    
     * @param type       The type representing this class
     * @param elements   Vector containing the Type and name of each property
     * @param extendType The type representing the extended class (or null)
     * @param attributes Vector containing the attribute types and names
     */
    protected AS3BeanHelperWriter(Emitter emitter, TypeEntry type,
                                   Vector elements, TypeEntry extendType,
                                   Vector attributes, Set reservedPropNames) {

        super(emitter, type.getName() + "_Helper", "helper");

        this.type = type;
        this.elements = elements;
        this.attributes = attributes;
        this.extendType = extendType;
        this.reservedPropNames = reservedPropNames;

        // is this a complex type that is derived from other types
        // by restriction?  if so, set the policy of the generated
        // TypeDescription to ignore metadata associated with
        // superclasses, as restricted types are required to
        // define their entire content model.  Hence the type
        // description associated with the current type provides
        // all of the types (and only those types) allowed in
        // the restricted derivation.
        if ((null != extendType)
                && (null
                != SchemaUtils.getComplexElementRestrictionBase(
                        type.getNode(), emitter.getSymbolTable()))) {
            this.canSearchParents = false;
        } else {
            this.canSearchParents = true;
        }
    }    // ctor

    /**
     * The bean helper class may be its own class, or it may be
     * embedded within the bean class.  If it's embedded within the
     * bean class, the JavaBeanWriter will set JavaBeanHelperWriter's
     * PrintWriter to its own.
     * 
     * @param pw 
     */
    protected void setPrintWriter(PrintWriter pw) {
        this.wrapperPW = pw;
    }    // setPrintWriter

    /**
     * The default behaviour (of super.getPrintWriter) is, given the
     * file name, create a PrintWriter for it.  If the bean helper
     * that this class is generating is embedded within a bean, then
     * the PrintWriter returned by this method is the JavaBeanWriter's
     * PrintWriter.  Otherwise super.getPrintWriter is called.
     * 
     * @param filename 
     * @return 
     * @throws IOException 
     */
    protected PrintWriter getPrintWriter(String filename) throws IOException {

        return (wrapperPW == null)
                ? super.getPrintWriter(filename)
                : wrapperPW;
    }    // getPrintWriter

    /**
     * Only register the filename if the bean helper is not wrapped
     * within a bean.
     * 
     * @param file 
     */
    protected void registerFile(String file) {

        if (wrapperPW == null) {
            super.registerFile(file);
        }
    }    // registerFile

    /**
     * Return the string:  "Generating <file>".
     * only if we are going to generate a new file.
     * 
     * @param file 
     * @return 
     */
    protected String verboseMessage(String file) {

        if (wrapperPW == null) {
            return super.verboseMessage(file);
        } else {
            return null;
        }
    }    // verboseMessage

    /**
     * Only write the file header if the bean helper is not wrapped
     * within a bean.
     * 
     * @param pw 
     * @throws IOException 
     */
    protected void writeFileHeader(PrintWriter pw) throws IOException {

        if (wrapperPW == null) {
            super.writeFileHeader(pw);
        }
    }    // writeFileHeader

    /**
     * Generate the file body for the bean helper.
     * 
     * @param pw 
     * @throws IOException 
     */
    protected void writeFileBody(PrintWriter pw) throws IOException {

        writeMetaData(pw);
        writeSerializer(pw);
        writeDeserializer(pw);
    }    // writeFileBody

    /**
     * Only write the file footer if the bean helper is not
     * wrapped within a bean.
     * 
     * @param pw 
     * @throws IOException 
     */
    protected void writeFileFooter(PrintWriter pw) throws IOException {

        if (wrapperPW == null) {
            super.writeFileFooter(pw);
        }
    }    // writeFileFooter

    /**
     * Only close the PrintWriter if the PrintWriter belongs to
     * this class.  If the bean helper is embedded within a bean
     * then the PrintWriter belongs to JavaBeanWriter and THAT
     * class is responsible for closing the PrintWriter.
     * 
     * @param pw 
     */
    protected void closePrintWriter(PrintWriter pw) {

        // If the output of this writer is wrapped within
        // another writer (JavaBeanWriter), then THAT
        // writer will close the PrintWriter, not this one.
        if (wrapperPW == null) {
            pw.close();
        }
    }    // closePrintWriter

    /**
     * write MetaData code
     * 
     * @param pw 
     * @throws IOException 
     */
    protected void writeMetaData(PrintWriter pw) throws IOException {

    }

    /**
     * Utility function to get the bean property name (as will be returned
     * by the Introspector) for a given field name.  This just means
     * we capitalize the first character if the second character is
     * capitalized.  Example: a field named "fOO" will turn into
     * getter/setter methods "getFOO()/setFOO()".  So when the Introspector
     * looks at that bean, the property name will be "FOO", not "fOO" due
     * to the rules in the JavaBeans spec.  So this makes sure the
     * metadata will match. <p>
     *
     * The method also makes sure that the returned property name is not in
     * the set of reserved properties as defined by {@link #reservedPropNames}.     
     *  
     * @param fieldName 
     * @return 
     */
    private String getAsFieldName(String fieldName) {

        // If there's a second character, and it is uppercase, then the
        // bean property name will have a capitalized first character
        // (because setURL() maps to a property named "URL", not "uRL")
        if ((fieldName.length() > 1)
                && Character.isUpperCase(fieldName.charAt(1))) {
            fieldName = Utils.capitalizeFirstChar(fieldName);
        }

        // Make sure the property name is not reserved.
        return JavaUtils.getUniqueValue(reservedPropNames, fieldName);
    }

    /**
     * write Serializer getter code and pass in meta data to avoid
     * undo introspection.
     * 
     * @param pw 
     * @throws IOException 
     */
    protected void writeSerializer(PrintWriter pw) throws IOException {

    }

    /**
     * write Deserializer getter code and pass in meta data to avoid
     * undo introspection.
     * 
     * @param pw 
     * @throws IOException 
     */
    protected void writeDeserializer(PrintWriter pw) throws IOException {


    }
}    // class JavaBeanHelperWriter
